package com.devbobcorn.nekorization.entities;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import com.devbobcorn.nekorization.Nekorization;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.animal.Cat;
import net.minecraft.world.level.Level;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
public class NekoEntity extends Cat {
	protected static final EntityDataAccessor<CompoundTag> DATA_HEAD_ENTITY = SynchedEntityData.defineId(NekoEntity.class, EntityDataSerializers.COMPOUND_TAG);
	private long timeEntitySatOnHead;

	public static final Map<Integer, String[]> TYPE_TEXS = new HashMap<>();
	public static final Map<Integer, ResourceLocation[]> EYES = new HashMap<>();
	public static final Map<Integer, ResourceLocation> HAIR_INNER = new HashMap<>();
	public static final Map<Integer, ResourceLocation> HAIR_OUTER = new HashMap<>();

	static {
		// Command: /data modify entity @e[type=nekorization:neko,limit=1] CatType set value 0
		// Prepare type names...
		TYPE_TEXS.put(0, new String[]{ "ragdoll", "orange" }); // tabby
		TYPE_TEXS.put(1, new String[]{ "ragdoll", "green" }); // black (tuxedo)
		TYPE_TEXS.put(2, new String[]{ "ragdoll", "green" }); // red
		TYPE_TEXS.put(3, new String[]{ "siamese", "blue" });
		TYPE_TEXS.put(4, new String[]{ "ragdoll", "yellow" }); // british_shorthair
		TYPE_TEXS.put(5, new String[]{ "ragdoll", "yellow_cyan" }); // calico
		TYPE_TEXS.put(6, new String[]{ "ragdoll", "blue" }); // persian
		TYPE_TEXS.put(7, new String[]{ "ragdoll", "blue" });
		TYPE_TEXS.put(8, new String[]{ "ragdoll", "yellow_cyan" }); // white
		TYPE_TEXS.put(9, new String[]{ "ragdoll", "lime" }); // jellie
		TYPE_TEXS.put(10, new String[]{ "ragdoll", "orange" }); // all_black
		// Prepare resource locations...
		for (int id : NekoEntity.TYPE_TEXS.keySet()){
			String[] typeTex = NekoEntity.TYPE_TEXS.get(id);
			ResourceLocation[] eyesLocs = {
				new ResourceLocation(Nekorization.MODID, "textures/entity/neko/eyes/" + typeTex[1] + "_0.png"),
				new ResourceLocation(Nekorization.MODID, "textures/entity/neko/eyes/" + typeTex[1] + "_1.png"),
				new ResourceLocation(Nekorization.MODID, "textures/entity/neko/eyes/" + typeTex[1] + "_2.png")
			};
			EYES.put(id, eyesLocs);
			HAIR_INNER.put(id, new ResourceLocation(Nekorization.MODID, "textures/entity/neko/hair/" + typeTex[0] + "_inner.png"));
			HAIR_OUTER.put(id, new ResourceLocation(Nekorization.MODID, "textures/entity/neko/hair/" + typeTex[0] + "_outer.png"));
		}
	}

	private static final Logger LOGGER = LogManager.getLogger("Neko Chan~");
	public static Field FDATA_TYPE_ID = null;
	private static boolean error = false;

	protected NekoEntity(EntityType<? extends Cat> type, Level world) {
		super(type, world);
	}

	public boolean isBaby() {
		//return getName().getString().startsWith("Baby");
		return false;
	}

	protected void defineSynchedData() {
		super.defineSynchedData();
		this.entityData.define(DATA_HEAD_ENTITY, new CompoundTag());
	}

	public void addAdditionalSaveData(CompoundTag tag) {
		super.addAdditionalSaveData(tag);
		if (!this.getHeadEntity().isEmpty()) {
			tag.put("HeadEntity", this.getHeadEntity());
		}
	}

	public void readAdditionalSaveData(CompoundTag tag) {
		super.readAdditionalSaveData(tag);
		if (tag.contains("HeadEntity", 10)) {
			this.setHeadEntity(tag.getCompound("HeadEntity"));
		}
	}

	public CompoundTag getHeadEntity() {
		return this.entityData.get(DATA_HEAD_ENTITY);
	}

	public boolean setEntityOnHead(CompoundTag tag) { // TODO
		if (!this.isPassenger() && this.onGround && !this.isInWater() && !this.isInPowderSnow) {
			if (this.getHeadEntity().isEmpty()) {
				this.setHeadEntity(tag);
				this.timeEntitySatOnHead = this.level.getGameTime();
				return true;
			} else return false;
		} else return false;
	}

	protected void setHeadEntity(CompoundTag tag) {
		this.entityData.set(DATA_HEAD_ENTITY, tag);
	}

	protected void removeEntitiesOnHead() {
		if (this.timeEntitySatOnHead + 20L < this.level.getGameTime()) {
			this.respawnEntityOnHead(this.getHeadEntity());
			this.setHeadEntity(new CompoundTag());
		}
	}

	private void respawnEntityOnHead(CompoundTag tag) {
		if (!this.level.isClientSide && !tag.isEmpty()) {
			EntityType.create(tag, this.level).ifPresent((entity) -> {
				if (entity instanceof TamableAnimal) {
					((TamableAnimal) entity).setOwnerUUID(this.uuid);
				}
				entity.setPos(this.getX(), this.getY() + (double) 0.7F, this.getZ());
				((ServerLevel) this.level).addWithUUID(entity);
			});
		}
	}

	// Some hack trick...
	private static boolean getTypeField() {
		try {
			FDATA_TYPE_ID = ObfuscationReflectionHelper.findField(Cat.class, "f_28104_");
		} catch (Exception e) {
			LOGGER.error("Cat type field not found!");
			error = true;
			return false;
		}
		return true;
	}

	@Override
	@SuppressWarnings("unchecked")
	public void setCatType(int type) { // Cancel the 0-10 range limit
		if (FDATA_TYPE_ID != null || (!error && getTypeField())) {
			try {
				final EntityDataAccessor<Integer> DATA_TYPE_ID = (EntityDataAccessor<Integer>) FDATA_TYPE_ID.get(this);
				this.entityData.set(DATA_TYPE_ID, type);
			} catch (Exception e) {
				e.printStackTrace();
				error = true;
				super.setCatType(type);
			}
		} else {
			super.setCatType(type);
		}
	}

	public ResourceLocation[] getEyes(){
		return EYES.getOrDefault(this.getCatType(), EYES.get(7)); // Ragdoll by default...
	}

	public ResourceLocation getInnerHair(){
		return HAIR_INNER.getOrDefault(this.getCatType(), HAIR_INNER.get(7)); // Ragdoll by default...
	}

	public ResourceLocation getOuterHair(){
		return HAIR_OUTER.getOrDefault(this.getCatType(), HAIR_OUTER.get(7)); // Ragdoll by default...
	}
}
